package cn.zyx.config.shiro.session;

import cn.zyx.common.properites.GlobalProperties;
import cn.zyx.common.utils.DateUtils;
import cn.zyx.common.utils.ServletsUtils;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;

/**
 * 系统安全认证实现类 -- 会话数据访问对象
 * 专注数据存取实现
 * 作用：
	* 将会话数据保存到存储介质（内存、Redis、数据库等）
	* 从存储介质加载会话数据
	* 更新存储中的会话数据
	* 从存储中删除会话数据
	* 获取所有活跃会话
 */
@Component("sessionDAO")
public class CacheSessionDAO extends EnterpriseCacheSessionDAO implements SessionDAO {

	private Logger logger = LoggerFactory.getLogger(getClass());

    public CacheSessionDAO() {
        super();
    }

	/**
	 * 创建session会话，返回session——id
	 * @param session
	 * @return
	 */
	@Override
	protected Serializable doCreate(Session session) {
		HttpServletRequest request = ServletsUtils.getRequest();
		super.doCreate(session);
		logger.debug("doCreate {} {}", session, request != null ? request.getRequestURI() : "");
		return session.getId();
	}

	/**
	 * 更新session会话
	 * @param session
	 */
    @Override
    protected void doUpdate(Session session) {
    	if (session == null || session.getId() == null) {
            return;
        }
    	HttpServletRequest request = ServletsUtils.getRequest();
		if (request != null){
			// 手动控制不更新SESSION
			String updateSession = request.getParameter("updateSession");
			if (GlobalProperties.FALSE.equals(updateSession) || GlobalProperties.NO.equals(updateSession)){
				return;
			}
		}
    	super.doUpdate(session);
    	logger.debug("update {} {}", session.getId(), request != null ? request.getRequestURI() : "");
    }

	/**
	 * 删除session会话
	 * @param session
	 */
    @Override
    protected void doDelete(Session session) {
    	if (session == null || session.getId() == null) {
            return;
        }
    	super.doDelete(session);
    	logger.debug("delete {} ", session.getId());
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
		logger.debug("doReadSession {}", sessionId);
		return super.doReadSession(sessionId);
    }

	/**
	 * 获取session会话
	 * @param sessionId
	 * @return
	 * @throws UnknownSessionException
	 */
    @Override
    public Session readSession(Serializable sessionId) throws UnknownSessionException {
    	try{
    		Session s = null;
    		HttpServletRequest request = ServletsUtils.getRequest();
    		if (request != null){
    			s = (Session) request.getAttribute("session_" + sessionId);
    		}
    		if (s != null){
    			return s;
    		}
    		Session session = super.readSession(sessionId);
    		logger.debug("readSession {} {}", sessionId, request != null ? request.getRequestURI() : "");
    		if (request != null && session != null){
    			request.setAttribute("session_" + sessionId, session);
    		}
    		return session;
    	}catch (UnknownSessionException e) {
			return null;
		}
    }

    /**
	 * 获取活动会话
	 * @param includeLeave 是否包括离线（最后访问时间大于3分钟为离线会话）
	 * @return
	 */
	@Override
	public Collection<Session> getActiveSessions(boolean includeLeave) {
		return getActiveSessions(includeLeave, null, null);
	}

    /**
	 * 获取活动会话
	 * @param includeLeave 是否包括离线（最后访问时间大于3分钟为离线会话）
	 * @param principal 根据登录者对象获取活动会话
	 * @param filterSession 不为空，则过滤掉（不包含）这个会话。
	 * @return
	 */
	@Override
	public Collection<Session> getActiveSessions(boolean includeLeave, Object principal, Session filterSession) {
		logger.debug("getActiveSessions {} {} {}", includeLeave,principal,filterSession);
		// 如果包括离线，并无登录者条件。
		if (includeLeave && principal == null){
			return getActiveSessions();
		}
		Set<Session> sessions = Sets.newHashSet();
		if(getActiveSessions() == null){
			return sessions;
		}
		for (Session session : getActiveSessions()){
			boolean isActiveSession = false;
			// 不包括离线并符合最后访问时间小于等于3分钟条件。
			if (includeLeave || DateUtils.pastMinutes(session.getLastAccessTime()) <= 3){
				isActiveSession = true;
			}
			// 符合登陆者条件。
			if (principal != null){
				PrincipalCollection pc = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
				if (principal.toString().equals(pc != null ? pc.getPrimaryPrincipal().toString() : StringUtils.EMPTY)){
					isActiveSession = true;
				}
			}
			// 过滤掉的SESSION
			if (filterSession != null && filterSession.getId().equals(session.getId())){
				isActiveSession = false;
			}
			if (isActiveSession){
				sessions.add(session);
			}
		}
		return sessions;
	}




}
